home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / txl / c!!20.lha / C++2.0 / groff.C++ next >
C/C++ Source or Header  |  1992-02-26  |  19KB  |  801 lines

  1. // -*- C++ -*-
  2. /* Copyright (C) 1990, 1991 Free Software Foundation, Inc.
  3.      Written by James Clark (jjc@jclark.uucp)
  4.  
  5. This file is part of groff.
  6.  
  7. groff is free software; you can redistribute it and/or modify it under
  8. the terms of the GNU General Public License as published by the Free
  9. Software Foundation; either version 1, or (at your option) any later
  10. version.
  11.  
  12. groff is distributed in the hope that it will be useful, but WITHOUT ANY
  13. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  15. for more details.
  16.  
  17. You should have received a copy of the GNU General Public License along
  18. with groff; see the file LICENSE.  If not, write to the Free Software
  19. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  20.  
  21. // A C++ implementation of groff.sh.
  22.  
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include <osfcn.h>
  26. #include <stdlib.h>
  27. #include <signal.h>
  28. #include <errno.h>
  29. #include <sys/types.h>
  30. #ifndef NO_SYS_WAIT_H
  31. #include <sys/wait.h>
  32. #endif /* not NO_SYS_WAIT_H */
  33.  
  34. #include "lib.h"
  35. #include "assert.h"
  36. #include "errarg.h"
  37. #include "error.h"
  38. #include "stringclass.h"
  39. #include "font.h"
  40.  
  41. #include "device.h"
  42.  
  43. #ifdef HAVE_PID_T
  44. typedef pid_t PID_T;
  45. #else
  46. typedef int PID_T;
  47. #endif
  48.  
  49. #ifdef HAVE_UNION_WAIT
  50. typedef union wait WAIT_STATUS_T;
  51. #else
  52. typedef int WAIT_STATUS_T;
  53. #endif
  54.  
  55. #ifdef NO_SYS_WAIT_H
  56. extern "C" {
  57.   PID_T wait(WAIT_STATUS_T *);
  58. }
  59. #endif /* NO_SYS_WAIT_H */
  60.  
  61.  
  62. #ifdef HAVE_UNION_WAIT
  63. /* Convert the argument which must be an lvalue of type union wait *
  64. to an int. */
  65. #define WTOI(s) (*(int *)&(s))
  66. #else
  67. #define WTOI(s) (s)
  68. #endif
  69.  
  70. #ifndef WIFEXITED
  71. #define WIFEXITED(s) ((WTOI(s) & 0377) == 0)
  72. #define WIFSTOPPED(s) ((WTOI(s) & 0377) == 0177)
  73. #define WIFSIGNALED(s) ((WTOI(s) & 0377) != 0 && ((WTOI(s) & 0377) != 0177))
  74. #endif /* WIFEXITED */
  75.  
  76. #ifndef WEXITSTATUS
  77. #define WEXITSTATUS(s) ((WTOI(s) >> 8) & 0377)
  78. #define WTERMSIG(s) (WTOI(s) & 0177)
  79. #define WSTOPSIG(s) ((WTOI(s) >> 8) & 0377)
  80. #endif /* not WEXITSTATUS */
  81.  
  82. #ifdef WAIT_COREDUMP_0200
  83. #define WCOREDUMPED(s) (WTOI(s) & 0200)
  84. #else
  85. #define WCOREDUMPED(s) 0
  86. #endif
  87.  
  88. const char *strsignal(int);
  89.  
  90. const char *ps_print[] = { (PSPRINT) 0 };
  91.  
  92. const char *dvi_print[] = { (DVIPRINT) 0 };
  93.  
  94. const char *grops[] = { "grops", 0 };
  95. const char *grotty[] = { "grotty", 0 };
  96. const char *grodvi[] = { "grodvi", 0 };
  97. const char *gxditview[] = { "gxditview", "-", 0 };
  98.  
  99. struct {
  100.   const char *pseudo_name;
  101.   const char *real_name;
  102.   const char *description;  // Description of device (used in help message).
  103.   const char **driver;        // Driver argument vector.
  104.   unsigned flags;        // Bitwise OR of 
  105. #define EQN_D_OPTION 01        /* Add -D option to eqn. */
  106. #define PIC_X_OPTION 02        /* Add -x option to pic. */
  107. #define PIC_P_OPTION 04        /* Add -p option to pic. */
  108. #define GROFF_OPTIONS 010   /* Driver understands -F and -v options. */
  109. #define XT_OPTION 020        /* Driver understands -title and -xrm options. */
  110. #define PRINT_OPTION 040    /* Understands -printCommand. */
  111.   const char *macro_file;   // -m option to pass to troff
  112.   const char **spooler;        // Spooler argument vector.
  113. } device_table[] = {
  114.   {
  115.     "ps",
  116.     "ps",
  117.     "PostScript",
  118.     grops,
  119.     EQN_D_OPTION|PIC_X_OPTION|PIC_P_OPTION|GROFF_OPTIONS,
  120.     "ps",
  121.     ps_print,
  122.     },
  123.   {
  124.     "ascii",
  125.     "ascii",
  126.     "ASCII",
  127.     grotty,
  128.     GROFF_OPTIONS,
  129.     "tty",
  130.     0
  131.     },
  132.   {
  133.     "latin1",
  134.     "latin1",
  135.     "ISO Latin-1",
  136.     grotty,
  137.     GROFF_OPTIONS,
  138.     "tty",
  139.     0
  140.     },
  141.   {
  142.     "dvi",
  143.     "dvi",
  144.     "TeX dvi format",
  145.     grodvi,
  146.     GROFF_OPTIONS|PIC_X_OPTION,
  147.     "dvi",
  148.     dvi_print,
  149.     },
  150.   {
  151.     "X100",
  152.     "X100",
  153.     "X11 previewer at 100dpi",
  154.     gxditview,
  155.     EQN_D_OPTION|PIC_X_OPTION|XT_OPTION,
  156.     "X",
  157.     0
  158.     },
  159.   {
  160.     "X75",
  161.     "X75",
  162.     "X11 previewer at 75dpi",
  163.     gxditview,
  164.     EQN_D_OPTION|PIC_X_OPTION|XT_OPTION,
  165.     "X",
  166.     0
  167.     },
  168.   {
  169.     "X100-12",
  170.     "X100-12",
  171.     "X11 previewer at 100dpi (optimized for 12 point text)",
  172.     gxditview,
  173.     EQN_D_OPTION|PIC_X_OPTION|XT_OPTION,
  174.     "X",
  175.     0
  176.     },
  177.   {
  178.     "X75-12",
  179.     "X75-12",
  180.     "X11 previewer at 75dpi (optimized for 12 point text)",
  181.     gxditview,
  182.     EQN_D_OPTION|PIC_X_OPTION|XT_OPTION,
  183.     "X",
  184.     0
  185.     },
  186.   {
  187.     "Xps",
  188.     "ps",
  189.     "X11 previewer with PostScript metrics",
  190.     gxditview,
  191.     EQN_D_OPTION|PIC_X_OPTION|PIC_P_OPTION|XT_OPTION|PRINT_OPTION,
  192.     "Xps",
  193.     0
  194.     },
  195. };
  196.  
  197. const int SOELIM_INDEX = 0;
  198. const int REFER_INDEX = SOELIM_INDEX + 1;
  199. const int PIC_INDEX = REFER_INDEX + 1;
  200. const int TBL_INDEX = PIC_INDEX + 1;
  201. const int EQN_INDEX = TBL_INDEX + 1;
  202. const int TROFF_INDEX = EQN_INDEX + 1;
  203. const int POST_INDEX = TROFF_INDEX + 1;
  204. const int SPOOL_INDEX = POST_INDEX + 1;
  205.  
  206. const int NCOMMANDS = SPOOL_INDEX + 1;
  207.  
  208. // Children exit with this status if the execvp failed.
  209. const int EXEC_FAILED_EXIT_STATUS = 0xff;
  210.  
  211. class possible_command {
  212.   char *name;
  213.   string args;
  214.   char **argv;
  215. public:
  216.   PID_T pid;
  217.  
  218.   possible_command();
  219.   ~possible_command();
  220.   void set_name(const char *);
  221.   const char *get_name();
  222.   void append_arg(const char *, const char * = 0);
  223.   void prepend_arg(const char *, const char * = 0);
  224.   void execp();
  225.   void clear_args();
  226.   void build_argv();
  227.   void print(int is_last, FILE *fp);
  228. };
  229.  
  230. int lflag = 0;
  231.  
  232. possible_command commands[NCOMMANDS];
  233.  
  234. int run_commands();
  235. void print_commands();
  236. void append_arg_to_string(const char *arg, string &str);
  237.  
  238. void usage();
  239. void help();
  240. void devices();
  241. void sys_fatal(const char *);
  242.  
  243. int main(int argc, char **argv)
  244. {
  245.   program_name = argv[0];
  246.   static char stderr_buf[BUFSIZ];
  247.   setbuf(stderr, stderr_buf);
  248.   string Pargs, Largs;
  249.   int Vflag = 0;
  250.   int zflag = 0;
  251.   int iflag = 0;
  252.   int opt;
  253.   const char *device = getenv("GROFF_TYPESETTER");
  254.   if (!device)
  255.     device = DEVICE;
  256.   commands[TROFF_INDEX].set_name("gtroff");
  257.   while ((opt = getopt(argc, argv,
  258.                "itpeRszavVhblCENZH:F:m:T:f:w:W:M:d:r:n:o:P:L:"))
  259.      != EOF) {
  260.     char buf[3];
  261.     buf[0] = '-';
  262.     buf[1] = opt;
  263.     buf[2] = '\0';
  264.     switch (opt) {
  265.     case 'i':
  266.       iflag = 1;
  267.       break;
  268.     case 't':
  269.       commands[TBL_INDEX].set_name("gtbl");
  270.       break;
  271.     case 'p':
  272.       commands[PIC_INDEX].set_name("gpic");
  273.       break;
  274.     case 'e':
  275.       commands[EQN_INDEX].set_name("geqn");
  276.       break;
  277.     case 's':
  278.       commands[SOELIM_INDEX].set_name("gsoelim");
  279.       break;
  280.     case 'R':
  281.       commands[REFER_INDEX].set_name("grefer");
  282.       break;
  283.     case 'z':
  284.     case 'a':
  285.       commands[TROFF_INDEX].append_arg(buf);
  286.       // fall through
  287.     case 'Z':
  288.       zflag++;
  289.       break;
  290.     case 'l':
  291.       lflag++;
  292.       break;
  293.     case 'V':
  294.       Vflag++;
  295.       break;
  296.     case 'v':
  297.       commands[POST_INDEX].append_arg(buf);
  298.       // fall through
  299.     case 'C':
  300.       commands[SOELIM_INDEX].append_arg(buf);
  301.       commands[PIC_INDEX].append_arg(buf);
  302.       commands[TBL_INDEX].append_arg(buf);
  303.       commands[EQN_INDEX].append_arg(buf);
  304.       commands[TROFF_INDEX].append_arg(buf);
  305.       break;
  306.     case 'N':
  307.       commands[EQN_INDEX].append_arg(buf);
  308.       break;
  309.     case 'h':
  310.       help();
  311.       break;
  312.     case 'E':
  313.     case 'b':
  314.       commands[TROFF_INDEX].append_arg(buf);
  315.       break;
  316.     case 'T':
  317.       device = optarg;
  318.       break;
  319.     case 'F':
  320.       font::command_line_font_dir(optarg);
  321.       commands[POST_INDEX].append_arg(buf, optarg);
  322.       // fall through
  323.     case 'f':
  324.     case 'o':
  325.     case 'm':
  326.     case 'r':
  327.     case 'M':
  328.     case 'H':
  329.     case 'd':
  330.     case 'n':
  331.     case 'w':
  332.     case 'W':
  333.       commands[TROFF_INDEX].append_arg(buf, optarg);
  334.       break;
  335.     case 'P':
  336.       Pargs += optarg;
  337.       Pargs += '\0';
  338.       break;
  339.     case 'L':
  340.       Largs += optarg;
  341.       Largs += '\0';
  342.       break;
  343.     case '?':
  344.       usage();
  345.       break;
  346.     default:
  347.       assert(0);
  348.       break;
  349.     }
  350.   }
  351.   int found = 0;
  352.   for (int device_index = 0;
  353.        device_index < sizeof(device_table)/sizeof(device_table[0]);
  354.        device_index++)
  355.     if (strcmp(device, device_table[device_index].pseudo_name) == 0) {
  356.       found = 1;
  357.       break;
  358.     }
  359.   if (!found) {
  360.     error("unknown device `%1'", device);
  361.     devices();
  362.     exit(1);
  363.   }
  364.   device = device_table[device_index].real_name;
  365.   if (device_table[device_index].macro_file != 0)
  366.     commands[TROFF_INDEX].prepend_arg("-m",
  367.                       device_table[device_index].macro_file);
  368.   commands[POST_INDEX].set_name(device_table[device_index].driver[0]);
  369.   if (!(device_table[device_index].flags & GROFF_OPTIONS))
  370.     commands[POST_INDEX].clear_args();
  371.   if ((device_table[device_index].flags & XT_OPTION)
  372.       && argc - optind == 1) {
  373.     commands[POST_INDEX].append_arg("-title");
  374.     commands[POST_INDEX].append_arg(argv[optind]);
  375.     commands[POST_INDEX].append_arg("-xrm");
  376.     commands[POST_INDEX].append_arg("*iconName:", argv[optind]);
  377.   }
  378.   if (device_table[device_index].flags & PRINT_OPTION) {
  379.     found = 0;
  380.     for (int di = 0; di < sizeof(device_table)/sizeof(device_table[0]); di++) {
  381.       if (strcmp(device, device_table[di].pseudo_name) == 0) {
  382.     found = 1;
  383.     break;
  384.       }
  385.     }
  386.     assert(found);
  387.     string print_string(device_table[di].driver[0]);
  388.     int i;
  389.     for (i = 1; device_table[di].driver[i]; i++)
  390.       append_arg_to_string(device_table[di].driver[i], print_string);
  391.     if (device_table[di].spooler) {
  392.       print_string += " |";
  393.       for (i = 0; device_table[di].spooler[i]; i++)
  394.     append_arg_to_string(device_table[di].spooler[i], print_string);
  395.     }
  396.     print_string += '\0';
  397.     commands[POST_INDEX].append_arg("-printCommand");
  398.     commands[POST_INDEX].append_arg(print_string.contents());
  399.   }
  400.   const char *p = Pargs.contents();
  401.   const char *end = p + Pargs.length();
  402.   while (p < end) {
  403.     commands[POST_INDEX].append_arg(p);
  404.     p = strchr(p, '\0') + 1;
  405.   }
  406.   int i;
  407.   for (i = 1; device_table[device_index].driver[i]; i++)
  408.     commands[POST_INDEX].append_arg(device_table[device_index].driver[i]);
  409.   if (device_table[device_index].flags & PIC_X_OPTION)
  410.     commands[PIC_INDEX].append_arg("-x");
  411.   if (device_table[device_index].flags & PIC_P_OPTION)
  412.     commands[PIC_INDEX].append_arg("-p");
  413.   if (device_table[device_index].flags & EQN_D_OPTION)
  414.     commands[EQN_INDEX].append_arg("-D");
  415.   if (lflag && device_table[device_index].spooler) {
  416.     commands[SPOOL_INDEX].set_name(device_table[device_index].spooler[0]);
  417.     p = Largs.contents();
  418.     end = p + Largs.length();
  419.     while (p < end) {
  420.       commands[SPOOL_INDEX].append_arg(p);
  421.       p = strchr(p, '\0') + 1;
  422.     }
  423.     for (i = 1; device_table[device_index].spooler[i]; i++)
  424.       commands[SPOOL_INDEX].append_arg(device_table[device_index].spooler[i]);
  425.   }
  426.   if (zflag) {
  427.     commands[POST_INDEX].set_name(0);
  428.     commands[SPOOL_INDEX].set_name(0);
  429.   }
  430.   commands[TROFF_INDEX].append_arg("-T", device);
  431.   int have_eqnchar = 0;
  432.   if (commands[EQN_INDEX].get_name() != 0) {
  433.     commands[EQN_INDEX].append_arg("-T", device);
  434.     font::set_device_name(device);
  435.     char *path = 0;
  436.     FILE *fp = font::open_file("eqnchar", &path);
  437.     if (fp) {
  438.       fclose(fp);
  439.       if (path[0] == '-' && path[1] != '\0')
  440.     commands[EQN_INDEX].append_arg("--");
  441.       commands[EQN_INDEX].append_arg(path);
  442.       delete path;
  443.       have_eqnchar = 1;
  444.     }
  445.   }
  446.   for (int first_index = 0; first_index < TROFF_INDEX; first_index++)
  447.     if (commands[first_index].get_name() != 0)
  448.       break;
  449.   if (optind < argc) {
  450.     if (argv[optind][0] == '-' && argv[optind][1] != '\0'
  451.     && (!have_eqnchar || first_index != EQN_INDEX))
  452.       commands[first_index].append_arg("--");
  453.     for (i = optind; i < argc; i++)
  454.       commands[first_index].append_arg(argv[i]);
  455.     if (iflag)
  456.       commands[first_index].append_arg("-");
  457.   }
  458.   if (have_eqnchar && (first_index != EQN_INDEX || optind >= argc))
  459.     commands[EQN_INDEX].append_arg("-");
  460.   if (Vflag) {
  461.     print_commands();
  462.     exit(0);
  463.   }
  464.   exit(run_commands());
  465. }
  466.  
  467. void print_commands()
  468. {
  469.   for (int last = SPOOL_INDEX; last >= 0; last--)
  470.     if (commands[last].get_name() != 0)
  471.       break;
  472.   for (int i = 0; i <= last; i++)
  473.     if (commands[i].get_name() != 0)
  474.       commands[i].print(i == last, stdout);
  475. }
  476.  
  477. // Run the commands. Return the code with which to exit.
  478.  
  479. int run_commands()
  480. {
  481.   for (int last = SPOOL_INDEX; last >= 0; last--)
  482.     if (commands[last].get_name() != 0)
  483.       break;
  484.   int last_input = 0;
  485.   int proc_count = 0;
  486.   for (int i = 0; i <= last; i++)
  487.     if (commands[i].get_name() != 0) {
  488.       proc_count++;
  489.       int pdes[2];
  490.       if (i != last) {
  491.     if (pipe(pdes) < 0)
  492.       sys_fatal("pipe");
  493.       }
  494. #ifdef HAVE_VFORK
  495.       PID_T pid = vfork();
  496.       if (pid < 0)
  497.     sys_fatal("vfork");
  498. #else /* !HAVE_VFORK */
  499.       PID_T pid = fork();
  500.       if (pid < 0)
  501.     sys_fatal("fork");
  502. #endif /* !HAVE_VFORK */
  503.       if (pid == 0) {
  504.     // child
  505.     if (last_input != 0) {
  506.       if (close(0) < 0)
  507.         sys_fatal("close");
  508.       if (dup(last_input) < 0)
  509.         sys_fatal("dup");
  510.       if (close(last_input) < 0)
  511.         sys_fatal("close");
  512.     }
  513.     if (i != last) {
  514.       if (close(1) < 0)
  515.         sys_fatal("close");
  516.       if (dup(pdes[1]) < 0)
  517.         sys_fatal("dup");
  518.       if (close(pdes[1]) < 0)
  519.         sys_fatal("close");
  520.       if (close(pdes[0]))
  521.         sys_fatal("close");
  522.     }
  523.     commands[i].execp();
  524.       }
  525.       // in the parent
  526.       if (last_input != 0) {
  527.     if (close(last_input) < 0)
  528.       sys_fatal("close");
  529.       }
  530.       if (i != last) {
  531.     if (close(pdes[1]) < 0)
  532.       sys_fatal("close");
  533.     last_input = pdes[0];
  534.       }
  535.       commands[i].pid = pid;
  536.     }
  537.   int ret = 0;
  538.   while (proc_count > 0) {
  539.     WAIT_STATUS_T status;
  540.     PID_T pid = wait(&status);
  541.     if (pid < 0)
  542.       sys_fatal("wait");
  543.     for (i = 0; i < NCOMMANDS; i++)
  544.       if (commands[i].pid == pid) {
  545.     --proc_count;
  546.     if (WIFSIGNALED(status)) {
  547.       int sig = WTERMSIG(status);
  548.       if (sig != SIGPIPE) {
  549.         error("%1: %2%3",
  550.           commands[i].get_name(),
  551.           strsignal(sig),
  552.           WCOREDUMPED(status) ? " (core dumped)" : "");
  553.         ret |= 2;
  554.       }
  555.     }
  556.     else if (WIFEXITED(status)) {
  557.       int exit_status = WEXITSTATUS(status);
  558.       if (exit_status == EXEC_FAILED_EXIT_STATUS)
  559.         ret |= 4;
  560.       else if (exit_status != 0)
  561.         ret |= 1;
  562.     }
  563.     else
  564.       error("unexpected status %1", WTOI(status));
  565.     break;
  566.       }
  567.   }
  568.   return ret;
  569. }
  570.  
  571. possible_command::possible_command()
  572. : pid(-1), name(0), argv(0)
  573. {
  574. }
  575.  
  576. possible_command::~possible_command()
  577. {
  578.   delete name;
  579.   delete argv;
  580. }
  581.  
  582. void possible_command::set_name(const char *s)
  583. {
  584.   name = strsave(s);
  585. }
  586.  
  587. const char *possible_command::get_name()
  588. {
  589.   return name;
  590. }
  591.  
  592. void possible_command::clear_args()
  593. {
  594.   args.clear();
  595. }
  596.  
  597. void possible_command::append_arg(const char *s, const char *t)
  598. {
  599.   args += s;
  600.   if (t)
  601.     args += t;
  602.   args += '\0';
  603. }
  604.  
  605. void possible_command::prepend_arg(const char *s, const char *t)
  606. {
  607.   string old(args);
  608.   args = s;
  609.   if (t)
  610.     args += t;
  611.   args += '\0';
  612.   args += old;
  613. }
  614.  
  615. void possible_command::build_argv()
  616. {
  617.   // Count the number of arguments.
  618.   int len = args.length();
  619.   int argc = 1;
  620.   char *p = 0;
  621.   if (len > 0) {
  622.     p = &args[0];
  623.     for (int i = 0; i < len; i++)
  624.       if (p[i] == '\0')
  625.     argc++;
  626.   }
  627.   // Build an argument vector.
  628.   argv = new char *[argc + 1];
  629.   argv[0] = name;
  630.   for (int i = 1; i < argc; i++) {
  631.     argv[i] = p;
  632.     p = strchr(p, '\0') + 1;
  633.   }
  634.   argv[argc] = 0;
  635. }
  636.  
  637. void possible_command::print(int is_last, FILE *fp)
  638. {
  639.   build_argv();
  640.   fputs(argv[0], fp);
  641.   string str;
  642.   for (int i = 1; argv[i] != 0; i++) {
  643.     str.clear();
  644.     append_arg_to_string(argv[i], str);
  645.     put_string(str, fp);
  646.   }
  647.   if (is_last)
  648.     putc('\n', fp);
  649.   else
  650.     fputs(" | ", fp);
  651. }
  652.  
  653. void append_arg_to_string(const char *arg, string &str)
  654. {
  655.   str += ' ';
  656.   int needs_quoting = 0;
  657.   int contains_single_quote = 0;
  658.   for (const char *p = arg; *p != '\0'; p++)
  659.     switch (*p) {
  660.     case ';':
  661.     case '&':
  662.     case '(':
  663.     case ')':
  664.     case '|':
  665.     case '^':
  666.     case '<':
  667.     case '>':
  668.     case '\n':
  669.     case ' ':
  670.     case '\t':
  671.     case '\\':
  672.     case '"':
  673.     case '$':
  674.       needs_quoting = 1;
  675.       break;
  676.     case '\'':
  677.       contains_single_quote = 1;
  678.       break;
  679.     }
  680.   if (contains_single_quote || arg[0] == '\0') {
  681.     str += '"';
  682.     for (p = arg; *p != '\0'; p++)
  683.       switch (*p) {
  684.       case '"':
  685.       case '\\':
  686.       case '$':
  687.     str += '\\';
  688.     // fall through
  689.       default:
  690.     str += *p;
  691.     break;
  692.       }
  693.     str += '"';
  694.   }
  695.   else if (needs_quoting) {
  696.     str += '\'';
  697.     str += arg;
  698.     str += '\'';
  699.   }
  700.   else
  701.     str += arg;
  702. }
  703.  
  704.  
  705. void possible_command::execp()
  706. {
  707.   build_argv();
  708.   execvp(name, argv);
  709.   error("couldn't exec %1: %2", name, strerror(errno));
  710.   fflush(stderr);        // just in case
  711.   _exit(EXEC_FAILED_EXIT_STATUS);
  712. }
  713.  
  714. void synopsis()
  715. {
  716.   fprintf(stderr,
  717. "usage: %s [-abehilpstvzCENRVZ] [-Hfile] [-Fdir] [-mname] [-Tdev] [-ffam]\n"
  718. "       [-wname] [-Wname] [ -Mdir] [-dcs] [-rcn] [-nnum] [-olist] [-Parg]\n"
  719. "       [-Larg] [files...]\n",
  720.       program_name);
  721. }
  722.  
  723. void devices()
  724. {
  725.   fputs("Available devices are:\n", stderr);
  726.   for (int i = 0; i < sizeof(device_table)/sizeof(device_table[0]); i++)
  727.     fprintf(stderr, "%s\t%s\n",
  728.         device_table[i].pseudo_name,
  729.         device_table[i].description);
  730. }
  731.  
  732. void help()
  733. {
  734.   synopsis();
  735.   fputs("\n"
  736. "-h\tprint this message\n"
  737. "-t\tpreprocess with tbl\n"
  738. "-p\tpreprocess with pic\n"
  739. "-e\tpreprocess with eqn\n"
  740. "-s\tpreprocess with soelim\n"
  741. "-R\tpreprocess with refer\n"
  742. "-Tdev\tuse device dev\n"
  743. "-mname\tread macros tmac.name\n"
  744. "-dcs\tdefine a string c as s\n"
  745. "-rcn\tdefine a number register c as n\n"
  746. "-nnum\tnumber first page n\n"
  747. "-olist\toutput only pages in list\n"
  748. "-ffam\tuse fam as the default font family\n"
  749. "-Fdir\tsearch directory dir for device directories\n"
  750. "-Mdir\tsearch dir for macro files\n"
  751. "-Hfile\tread hyphenation patterns from file\n"
  752. "-v\tprint version number\n"
  753. "-z\tsuppress formatted output\n"
  754. "-Z\tdon't postprocess\n"
  755. "-a\tproduce ASCII description of output\n"
  756. "-i\tread standard input after named input files\n"
  757. "-wname\tenable warning name\n"
  758. "-Wname\tinhibit warning name\n"
  759. "-E\tinhibit all errors\n"
  760. "-b\tprint backtraces with errors or warnings\n"
  761. "-l\tspool the output\n"
  762. "-C\tenable compatibility mode\n"
  763. "-V\tprint commands on stdout instead of running them\n"
  764. "-Parg\tpass arg to the postprocessor\n"
  765. "-Larg\tpass arg to the spooler\n"
  766. "-N\tdon't allow newlines within eqn delimiters\n"
  767. "\n",
  768.     stderr);
  769.   devices();
  770.   exit(0);
  771. }
  772.  
  773. void usage()
  774. {
  775.   synopsis();
  776.   fprintf(stderr, "%s -h gives more help\n", program_name);
  777.   exit(1);
  778. }
  779.  
  780. void sys_fatal(const char *s)
  781. {
  782.   fatal("%1: %2", s, strerror(errno));
  783. }
  784.  
  785. #ifdef HAVE_SYS_SIGLIST
  786. extern "C" {
  787.   extern char *sys_siglist[];
  788. }
  789. #endif /* HAVE_SYS_SIGLIST */
  790.   
  791. const char *strsignal(int n)
  792. {
  793.   static char buf[sizeof("Signal ") + 1 + INT_DIGITS];
  794. #ifdef HAVE_SYS_SIGLIST
  795.   if (n >= 0 && n < NSIG && sys_siglist[n] != 0)
  796.     return sys_siglist[n];
  797. #endif /* HAVE_SYS_SIGLIST */
  798.   sprintf(buf, "Signal %d", n);
  799.   return buf;
  800. }
  801.